package com.niuwa.p2p.core.file;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;

import org.apache.log4j.Logger;
import org.im4java.core.CompositeCmd;
import org.im4java.core.ConvertCmd;
import org.im4java.core.IM4JavaException;
import org.im4java.core.IMOperation;
import org.im4java.core.IdentifyCmd;
import org.im4java.process.ArrayListOutputConsumer;


/**
 * 
 * @title 图片处理工具 [目前因为linux环境问题用ImageMagick[作废]]
 *
 * @author tennyqin
 * @version 1.0
 * @created 2015年4月17日
 */

public class GraphicsMagick {

	public static String imageMagickPath = null;
	static {
        //只在windows环境下需要这个配置
		imageMagickPath = "C://Program Files (x86)//GraphicsMagick-1.3.21-Q8";
	}

	private static Logger logger = Logger.getLogger(GraphicsMagick.class); // 日志记录
	/**
	 * 居中切割图片(不支持gif图片切割) 1、如果源图宽高都小于目标宽高，则只压缩图片，不做切割
	 * 2、如果源图宽高都大于目标宽度，则根据宽度等比压缩后再居中切割 3、其它条件下，则压缩图片（不做缩放）后再居中切割
	 * 
	 * 该方法在知道源图宽度（sw）和高度（sh）的情况下使用
	 * 
	 * @param srcPath
	 *            源图路径
	 * @param desPath
	 *            切割图片保存路径
	 * @param sw
	 *            源图宽度
	 * @param sh
	 *            源图高度
	 * @param dw
	 *            切割目标宽度
	 * @param dh
	 *            切割目标高度
	 * @throws Exception
	 */
	public void cropImage(String srcPath, String desPath, int sw, int sh,
			int dw, int dh) throws Exception {

		if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0)
			return;

		IMOperation op = new IMOperation();
		op.addImage(srcPath);

		if ((sw <= dw) && (sh <= dh)) // 如果源图宽度和高度都小于目标宽高，则仅仅压缩图片
		{
			op.resize(sw, sh);
		}

		if ((sw <= dw) && (sh > dh))// 如果源图宽度小于目标宽度，并且源图高度大于目标高度
		{
			op.resize(sw, sh); // 压缩图片
			op.append().crop(sw, dh, 0, (sh - dh) / 2);// 切割图片
		}

		if ((sw > dw) && (sh <= dh))// 如果源宽度大于目标宽度，并且源高度小于目标高度
		{
			op.resize(sw, sh);
			op.append().crop(dw, sh, (sw - dw) / 2, 0);
		}

		if (sw > dw && sh > dh) // 如果源图宽、高都大于目标宽高
		{
			float ratiow = (float) dw / sw; // 宽度压缩比
			float ratioh = (float) dh / sh; // 高度压缩比

			if (ratiow >= ratioh) // 宽度压缩比小（等）于高度压缩比（是宽小于高的图片）
			{
				int ch = (int) (ratiow * sh); // 压缩后的图片高度

				op.resize(dw, null); // 按目标宽度压缩图片
				op.append().crop(dw, dh, 0, (ch > dh) ? ((ch - dh) / 2) : 0); // 根据高度居中切割压缩后的图片
			} else // （宽大于高的图片）
			{
				int cw = (int) (ratioh * sw); // 压缩后的图片宽度

				op.resize(cw, null); // 按计算的宽度进行压缩
				op.append().crop(dw, dh, (cw > dw) ? ((cw - dw) / 2) : 0, 0); // 根据宽度居中切割压缩后的图片

			}
		}
		op.addImage(desPath);
		ConvertCmd convert = new ConvertCmd(true);
		String osName = System.getProperty("os.name").toLowerCase();
		if (osName.indexOf("win") != -1) {
			// linux下不要设置此值，不然会报错
			convert.setSearchPath(imageMagickPath);
		}
		convert.run(op);
	}

	/**
	 * 
	 * 根据坐标裁剪图片
	 * 
	 * @param srcPath
	 *            要裁剪图片的路径
	 * @param newPath
	 *            裁剪图片后的路径
	 * @param x
	 *            起始横坐标
	 * @param y
	 *            起始挫坐标
	 * @param x1
	 *            结束横坐标
	 * @param y1
	 *            结束挫坐标
	 */

	public static void cutImage(String srcPath, String newPath, int x, int y,
			int x1, int y1) throws Exception {
		int width = x1 - x;
		int height = y1 - y;
		IMOperation op = new IMOperation();
		op.addImage(srcPath);
		/**
		 * width： 裁剪的宽度 height：裁剪的高度 x： 裁剪的横坐标 y： 裁剪的挫坐标
		 */
		op.crop(width, height, x, y);
		op.addImage(newPath);
		ConvertCmd convert = new ConvertCmd(true);
		String osName = System.getProperty("os.name").toLowerCase();
		if (osName.indexOf("win") != -1) {
			// linux下不要设置此值，不然会报错
			convert.setSearchPath(imageMagickPath);
		}
		convert.run(op);
	}

	/**
	 * 
	 * 根据尺寸缩放图片
	 * 
	 * @param width
	 *            缩放后的图片宽度
	 * @param height
	 *            缩放后的图片高度
	 * @param srcPath
	 *            源图片路径
	 * @param newPath
	 *            缩放后图片的路径
	 */
	public static void cutImage(int width, int height, String srcPath,
			String newPath) throws Exception {
		IMOperation op = new IMOperation();
		op.addImage(srcPath);
		op.resize(width, height);
		op.addImage(newPath);
		ConvertCmd convert = new ConvertCmd(true);
		String osName = System.getProperty("os.name").toLowerCase();
		if (osName.indexOf("win") != -1) {
			// linux下不要设置此值，不然会报错
			convert.setSearchPath(imageMagickPath);
		}
		convert.run(op);
	}

	/**
	 * 根据宽度缩放图片
	 * 
	 * @param width
	 *            缩放后的图片宽度
	 * @param srcPath
	 *            源图片路径
	 * @param newPath
	 *            缩放后图片的路径
	 */
	public static void cutImage(int width, String srcPath, String newPath)
			throws Exception {
		IMOperation op = new IMOperation();
		op.addImage(srcPath);
		op.resize(width, null);
		op.addImage(newPath);
		ConvertCmd convert = new ConvertCmd(true);
		String osName = System.getProperty("os.name").toLowerCase();
		if (osName.indexOf("win") != -1) {
			// linux下不要设置此值，不然会报错
			convert.setSearchPath(imageMagickPath);
		}
		convert.run(op);
	}

	/**
	 * 给图片加水印
	 * 
	 * @param srcPath
	 *            源图片路径
	 */
	public static void addImgText(String srcPath) throws Exception {
		IMOperation op = new IMOperation();
		op.font("Arial").gravity("southeast").pointsize(18).fill("#BCBFC8")
				.draw("text 5,5 niuwap2p.com");
		op.addImage();
		op.addImage();
		ConvertCmd convert = new ConvertCmd(true);
		String osName = System.getProperty("os.name").toLowerCase();
		if (osName.indexOf("win") != -1) {
			// linux下不要设置此值，不然会报错
			convert.setSearchPath(imageMagickPath);
		}
		convert.run(op, srcPath, srcPath);
	}

	/**
	 * 图片信息
	 * 
	 * @param imagePath
	 * @return
	 */
	public static String getImageInfo(String imagePath) {
		String line = null;
		try {
			IMOperation op = new IMOperation();
			op.format("width:%w,height:%h,path:%d%f,size:%b%[EXIF:DateTimeOriginal]");
			op.addImage(1);
			IdentifyCmd identifyCmd = new IdentifyCmd(true);
			String osName = System.getProperty("os.name").toLowerCase();
			if (osName.indexOf("win") != -1) {
				// linux下不要设置此值，不然会报错
				identifyCmd.setSearchPath(imageMagickPath);
			}
			ArrayListOutputConsumer output = new ArrayListOutputConsumer();
			identifyCmd.setOutputConsumer(output);
			identifyCmd.run(op, imagePath);
			ArrayList<String> cmdOutput = output.getOutput();
			assert cmdOutput.size() == 1;
			line = cmdOutput.get(0);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return line;
	}

	/**
	 * 根据尺寸缩放图片[等比例缩放:参数height为null,按宽度缩放比例缩放;参数width为null,按高度缩放比例缩放]
	 * 
	 * @param imagePath
	 *            源图片路径
	 * @param newPath
	 *            处理后图片路径
	 * @param width
	 *            缩放后的图片宽度
	 * @param height
	 *            缩放后的图片高度
	 * @return 返回true说明缩放成功,否则失败
	 */
	public static boolean zoomImage(String imagePath, String newPath, Integer width,
			Integer height) {
		boolean flag = false;
		try {
			IMOperation op = new IMOperation();
			op.addImage(imagePath);
			if (width == null) {// 根据高度缩放图片
				op.resize(null, height);
			} else if (height == null) {// 根据宽度缩放图片
				op.resize(width);
			} else {
				op.resize(width, height);
			}
			op.addImage(newPath);
			ConvertCmd convert = new ConvertCmd(true);
			String osName = System.getProperty("os.name").toLowerCase();
			if (osName.indexOf("win") != -1) {
				// linux下不要设置此值，不然会报错
				convert.setSearchPath(imageMagickPath);
			}
			convert.run(op);
			flag = true;
		} catch (IOException e) {
			System.out.println("文件读取错误!");
			flag = false;
		} catch (InterruptedException e) {
			flag = false;
		} catch (IM4JavaException e) {
			flag = false;
		} finally {
		}
		return flag;
	}

	/**
	 * 图片旋转
	 * 
	 * @param imagePath
	 *            源图片路径
	 * @param newPath
	 *            处理后图片路径
	 * @param degree
	 *            旋转角度
	 */
	public boolean rotate(String imagePath, String newPath, double degree) {
		boolean flag = false;
		try {
			// 1.将角度转换到0-360度之间
			degree = degree % 360;
			if (degree <= 0) {
				degree = 360 + degree;
			}
			IMOperation op = new IMOperation();
			op.addImage(imagePath);
			op.rotate(degree);
			op.addImage(newPath);
			ConvertCmd cmd = new ConvertCmd(true);
			String osName = System.getProperty("os.name").toLowerCase();
			if (osName.indexOf("win") != -1) {
				// linux下不要设置此值，不然会报错
				cmd.setSearchPath(imageMagickPath);
			}
			cmd.run(op);
			flag = true;
		} catch (Exception e) {
			flag = false;
			System.out.println("图片旋转失败!");
		}
		return flag;
	}

	/**
	 * 根据尺寸缩放图片
	 * 
	 * @param width
	 *            缩放后的图片宽度
	 * @param height
	 *            缩放后的图片高度
	 * @param srcPath
	 *            源图片路径
	 * @param newPath
	 *            缩放后图片的路径
	 */
	public static void zoomImage(Integer width, Integer height, String srcPath,
			String newPath) throws Exception {
		IMOperation op = new IMOperation();
		op.addImage(srcPath);
		if (width == null) {// 根据高度缩放图片
			op.resize(null, height);
		} else if (height == null) {// 根据宽度缩放图片
			op.resize(width, null);
		} else {
			op.resize(width, height);
		}
		op.addImage(newPath);
		ConvertCmd convert = new ConvertCmd(true);
		String osName = System.getProperty("os.name").toLowerCase();
		if (osName.indexOf("win") != -1) {
			// linux下不要设置此值，不然会报错
			convert.setSearchPath(imageMagickPath);
		}
		convert.run(op);
	}

	/**
	 * 给图片加水印
	 * 
	 * @param srcPath
	 *            源图片路径
	 */
	public static void addImgText(String srcPath, String content)
			throws Exception {
		IMOperation op = new IMOperation();
		op.font("Arial");
		op.gravity("southeast");
		op.pointsize(18).fill("#BCBFC8").draw("text 0,0 " + content); // ("x1 x2 x3 x4")
																		// x1
																		// 格式，x2
																		// x轴距离
																		// x3
																		// y轴距离
																		// x4名称
		op.addImage();
		op.addImage();
		ConvertCmd convert = new ConvertCmd(true);
		String osName = System.getProperty("os.name").toLowerCase();
		if (osName.indexOf("win") != -1) {
			// linux下不要设置此值，不然会报错
			convert.setSearchPath(imageMagickPath);
		}
		try {
			convert.run(op, srcPath, srcPath);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 图片水印
	 * 
	 * @param srcImagePath
	 *            源图片
	 * @param waterImagePath
	 *            水印
	 * @param destImagePath
	 *            生成图片
	 * @param gravity
	 *            图片位置
	 * @param dissolve
	 *            水印透明度
	 */
	public static void waterMark(String waterImagePath, String srcImagePath,
			String destImagePath, String gravity, int dissolve) {
		IMOperation op = new IMOperation();
		op.gravity(gravity);
		op.dissolve(dissolve);
		op.addImage(waterImagePath);
		op.addImage(srcImagePath);
		op.addImage(destImagePath);
		CompositeCmd cmd = new CompositeCmd(true);
		String osName = System.getProperty("os.name").toLowerCase();
		if (osName.indexOf("win") != -1) {
			// linux下不要设置此值，不然会报错
			cmd.setSearchPath(imageMagickPath);
		}
		try {
			cmd.run(op);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (IM4JavaException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 图片等比例压缩 [默认原图片大小]
	 * 
	 * @param imagePath
	 *            文件路径
	 * @param scaleSize
	 *            比例大小图片压缩比，有效值范围是0.0-100.0，数值越大，缩略图越清晰
	 * @throws IM4JavaException
	 * @throws InterruptedException
	 * @throws IOException
	 */
	public static void scaleImage(String imagePath, String newpath,
			Double scaleSize) throws IOException, InterruptedException,
			IM4JavaException {
		IMOperation op = new IMOperation();
		// 待处理图片的绝对路径
		op.addImage(imagePath);
		// 图片压缩比，有效值范围是0.0-100.0，数值越大，缩略图越清晰
		op.quality(scaleSize);
		// width 和height可以是原图的尺寸，也可以是按比例处理后的尺寸
		op.addRawArgs("-resize", getWidth(imagePath) + "x"
				+ getHeight(imagePath));
		op.addRawArgs("-gravity", "center");
		// 处理后图片的绝对路径
		op.addImage(newpath);
		// 如果使用ImageMagick，设为false,使用GraphicsMagick，就设为true，默认为false
		ConvertCmd convert = new ConvertCmd(true);
		String osName = System.getProperty("os.name").toLowerCase();
		if (osName.indexOf("win") != -1) {
			logger.error("进入了win系统。。。。。");
			// linux下不要设置此值，不然会报错
			convert.setSearchPath(imageMagickPath);
		}
		logger.error("我还没有出异常1......");
		convert.run(op);
		logger.error("我还没有出异常2......");
	}

	/**
	 * 图片等比例压缩 [传入图片大小参数]
	 * 
	 * @param imagePath
	 *            文件路径
	 * @param scaleSize
	 *            比例大小图片压缩比，有效值范围是0.0-100.0，数值越大，缩略图越清晰
	 */
	public static void scaleImage(String imagePath, String newpath,
			Double scaleSize, int width, int height) {
		IMOperation op = new IMOperation();
		// 待处理图片的绝对路径
		op.addImage(imagePath);
		// 图片压缩比，有效值范围是0.0-100.0，数值越大，缩略图越清晰
		op.quality(scaleSize);
		// width 和height可以是原图的尺寸，也可以是按比例处理后的尺寸
		op.addRawArgs("-resize", width + "x" + height);
		op.addRawArgs("-gravity", "center");
		// 处理后图片的绝对路径
		op.addImage(newpath);
		// 如果使用ImageMagick，设为false,使用GraphicsMagick，就设为true，默认为false
		ConvertCmd convert = new ConvertCmd(true);
		String osName = System.getProperty("os.name").toLowerCase();
		if (osName.indexOf("win") != -1) {
			// linux下不要设置此值，不然会报错
			convert.setSearchPath(imageMagickPath);
		}
		try {
			convert.run(op);
		} catch (IOException | InterruptedException | IM4JavaException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 图片信息
	 * 
	 * @param imagePath
	 *            文件路径
	 * @return
	 */
	public static String showImageInfo(String imagePath) {
		String line = null;
		try {
			IMOperation op = new IMOperation();
			op.format("width:%w,height:%h,path:%d%f,size:%b%[EXIF:DateTimeOriginal]");
			op.addImage(1);
			IdentifyCmd identifyCmd = new IdentifyCmd(true);
			String osName = System.getProperty("os.name").toLowerCase();
			if (osName.indexOf("win") != -1) {
				// linux下不要设置此值，不然会报错
				identifyCmd.setSearchPath(imageMagickPath);
			}
			ArrayListOutputConsumer output = new ArrayListOutputConsumer();
			identifyCmd.setOutputConsumer(output);
			identifyCmd.run(op, imagePath);
			ArrayList<String> cmdOutput = output.getOutput();
			assert cmdOutput.size() == 1;
			line = cmdOutput.get(0);

		} catch (Exception e) {
			e.printStackTrace();
		}
		return line;
	}

	/**
	 * 图片合成
	 * 
	 * @param args
	 * @param maxWidth
	 * @param maxHeight
	 * @param newpath
	 * @param mrg
	 * @param type
	 *            1:横,2:竖
	 */
	public static void montage(String[] args, Integer maxWidth,
			Integer maxHeight, String newpath, Integer mrg, String type) {
		IMOperation op = new IMOperation();
		ConvertCmd cmd = new ConvertCmd(true);
		String osName = System.getProperty("os.name").toLowerCase();
		if (osName.indexOf("win") != -1) {
			// linux下不要设置此值，不然会报错
			cmd.setSearchPath(imageMagickPath);
		}
		String thumb_size = maxWidth + "x" + maxHeight + "^";
		String extent = maxWidth + "x" + maxHeight;
		if ("1".equals(type)) {
			op.addRawArgs("+append");
		} else if ("2".equals(type)) {
			op.addRawArgs("-append");
		}

		op.addRawArgs("-thumbnail", thumb_size);
		op.addRawArgs("-gravity", "center");
		op.addRawArgs("-extent", extent);

		Integer border_w = maxWidth / 40;
		op.addRawArgs("-border", border_w + "x" + border_w);
		op.addRawArgs("-bordercolor", "#ccc");

		op.addRawArgs("-border", 1 + "x" + 1);
		op.addRawArgs("-bordercolor", "#fff");

		for (String img : args) {
			op.addImage(img);
		}
		if ("1".equals(type)) {
			Integer whole_width = ((mrg / 2) + 1 + border_w + maxWidth
					+ border_w + (mrg / 2) + 1)
					* args.length - mrg;
			Integer whole_height = maxHeight + border_w + 1;
			op.addRawArgs("-extent", whole_width + "x" + whole_height);
		} else if ("2".equals(type)) {
			Integer whole_width = maxWidth + border_w + 1;
			Integer whole_height = ((mrg / 2) + 1 + border_w + maxHeight
					+ border_w + (mrg / 2) + 1)
					* args.length - mrg;
			op.addRawArgs("-extent", whole_width + "x" + whole_height);
		}
		op.addImage(newpath);
		try {
			cmd.run(op);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取图片大小
	 * 
	 * @param imagePath
	 */
	public static int getSize(String imagePath) {
		int size = 0;
		FileInputStream inputStream = null;
		try {
			inputStream = new FileInputStream(imagePath);
			size = inputStream.available();
			inputStream.close();
			inputStream = null;
		} catch (FileNotFoundException e) {
			size = 0;
			System.out.println("文件未找到!");
		} catch (IOException e) {
			size = 0;
			System.out.println("读取文件大小错误!");
		} finally {
			// 可能异常为关闭输入流,所以需要关闭输入流
			if (null != inputStream) {
				try {
					inputStream.close();
				} catch (IOException e) {
					System.out.println("关闭文件读入流异常");
				}
				inputStream = null;
			}
		}
		return size;
	}

	/**
	 * 获得图片的宽度
	 * 
	 * @param filePath
	 *            文件路径
	 * 
	 * @return 图片宽度
	 */

	public static int getWidth(String imagePath) {
		int line = 0;
		try {
			IMOperation op = new IMOperation();
			op.format("%w"); // 设置获取宽度参数
			op.addImage(1);
			IdentifyCmd identifyCmd = new IdentifyCmd(true);
			String osName = System.getProperty("os.name").toLowerCase();
			if (osName.indexOf("win") != -1) {
				// linux下不要设置此值，不然会报错
				identifyCmd.setSearchPath(imageMagickPath);
			}
			ArrayListOutputConsumer output = new ArrayListOutputConsumer();
			identifyCmd.setOutputConsumer(output);
			identifyCmd.run(op, imagePath);
			ArrayList<String> cmdOutput = output.getOutput();
			assert cmdOutput.size() == 1;
			line = Integer.parseInt(cmdOutput.get(0));
		} catch (Exception e) {
			line = 0;
			System.out.println("运行指令出错!");
		}
		return line;
	}

	/**
	 * 获得图片的高度
	 * 
	 * @param imagePath
	 *            文件路径
	 * 
	 * @return 图片高度
	 */
	public static int getHeight(String imagePath) {
		int line = 0;
		try {

			IMOperation op = new IMOperation();
			op.format("%h"); // 设置获取高度参数
			op.addImage(1);
			IdentifyCmd identifyCmd = new IdentifyCmd(true);
			String osName = System.getProperty("os.name").toLowerCase();
			if (osName.indexOf("win") != -1) {
				// linux下不要设置此值，不然会报错
				identifyCmd.setSearchPath(imageMagickPath);
			}
			ArrayListOutputConsumer output = new ArrayListOutputConsumer();
			identifyCmd.setOutputConsumer(output);
			identifyCmd.run(op, imagePath);
			ArrayList<String> cmdOutput = output.getOutput();
			assert cmdOutput.size() == 1;
			line = Integer.parseInt(cmdOutput.get(0));
		} catch (Exception e) {
			line = 0;
			System.out.println("运行指令出错!" + e.toString());
		}
		return line;
	}

	public static void main(String[] args) {
		String waterMark="F:\\image\\sy.png";
		String f1 = "F:\\image\\1.jpg";
		String f2 = "F:\\image\\2.jpg";
		String f3 = "F:\\image\\bb\\imgupload2.png";
		try {
			// cutImage(680, 720, f1, f2);
			 scaleImage(f1, f2, 100.0);
			// waterMark(waterMark,f1,f2,"center",80);
		//	zoomImage(f1,f2,300,null);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}